﻿using System;

using System.Collections.Generic;
using System.Text;
using PublicTransport.Services.BO;
using PublicTransport.DAL;
using PublicTransport.DAL.DTO;

namespace PublicTransport.Services
{
    /// <summary>   Service, ktorý pracuje s údajmi o staniciach  </summary>
    class StationService : IStationService
    {
       IStationDao stationDao;

       private static StationService instance;

       /// <summary>    Inštancia, ktorá je zdieľaná </summary>
       ///
       /// <value>  The instance. </value>
       public static StationService Instance
       {
          get 
          {
             if (instance == null)
             {
                 instance = new StationService();
             }
             return instance;
          }
        }

       private List<StationDTO> allStations = null;

        /// <summary>   Vytvorí inštanciu StationDao a uchová si referenciu </summary>
        private StationService()
        {
            this.stationDao = new StationDao();
        }

        /// <summary>   Vráti menný zoznam všetkých zastávok. </summary>
        ///
        /// <returns>  Všetky názvy staníc </returns>
        public List<String> GetAllStationNames()
        {
            return stationDao.GetAllStationNames();
        }

        /// <summary>   Vráti najbližšie stanice podľa zadaných koordinátov. </summary>
        ///
        /// <param name="lat">  zemepisná šírka. </param>
        /// <param name="lon">  zemepisná dĺžka. </param>
        ///
        /// <returns>   Zoradený zoznam najbližších staníc. </returns>
        public SortedList<double,StationDTO> GetNearestStations(double lat, double lon)
        {
            if (allStations == null)
            {
                allStations = stationDao.GetAllStations();
            }

            SortedList<double, StationDTO> nearestStations = new SortedList<double,StationDTO>();

            foreach (StationDTO station in allStations)
            {
                if (station.Latitude != null && station.Longtitude != null)
                {
                    nearestStations.Add(distance(lat, lon, (double)station.Latitude, (double)station.Longtitude), station);
                }
            }


            return nearestStations;
        }

        /// <summary>   Vyráta vzdialenosť medzi dvoma zem. bodmi. </summary>
        ///
        /// <param name="lat1"> Latitude prvého bodu. </param>
        /// <param name="lon1"> Longitude prvého bodu </param>
        /// <param name="lat2"> Latitude druhého bodu. </param>
        /// <param name="lon2"> Longitude druhého bodu  </param>
        ///
        /// <returns>   . </returns>

        private double distance(double lat1, double lon1, double lat2, double lon2)
        {
            double theta = lon1 - lon2;
            double dist = Math.Sin(deg2rad(lat1)) * Math.Sin(deg2rad(lat2)) +
                          Math.Cos(deg2rad(lat1)) * Math.Cos(deg2rad(lat2)) *
                          Math.Cos(deg2rad(theta));
            dist = Math.Acos(dist);
            dist = rad2deg(dist);
            dist = dist * 60 * 1.1515;

            //v kilometroch
            dist = dist * 1.609344;
            /*
            if (unit == 'K')
            {
                dist = dist * 1.609344;
            }
            else if (unit == 'N')
            {
                dist = dist * 0.8684;
            }
            */
            return (dist);
        }

        /// <summary>   Premieňa stupne na radiány </summary>
        ///
        /// <param name="deg">  Stupne ktoré chceme premeniť. </param>
        ///
        /// <returns>  Radiány </returns>

        private double deg2rad(double deg)
        {
            return (deg * Math.PI / 180.0);
        }

        /// <summary>   Premieňa radiány na stupne </summary>
        ///
        /// <param name="rad"> Radiány </param>
        ///
        /// <returns>  Premenené stupne </returns>

        private double rad2deg(double rad)
        {
            return (rad / Math.PI * 180.0);
        }

        /// <summary>   Vráti stanicu podľa zadaného názvu. </summary>
        ///
        /// <param name="nazov">    presný názov stanice. </param>
        ///
        /// <returns>   Nájdena stanica. Null ak nenájdena. </returns>
        public StationDTO GetStation(string nazov)
        {
            return stationDao.GetStation(nazov);
        }

    }
}
